<?php
/**
 * Charge les données d'un item et les informations relative à
 * - son BPO
 * - sa catégorie
 * - son prix (comming soon ...)
 * @author  Joseph Lemoine - lemoine.joseph@gmail.com
 * @version 3
 */
class eveitem extends Dao {

    /**
     * Banque d'item déjà chargé
     * @var	array
     */
    protected static $_loadedItem;

    /**
     * Nom de la base de donnée liée
     * @var     string
     */
    protected $_bdd = "EVE";

    /**
     * Nom de la table
     * @var     string
     */
    protected $_table = "invtypes";

    /**
     * Définie l'accès en lecture seule ou non de la table
     * @var	bool
     */
    protected $_readOnly = TRUE;

    /**
     * Contient les informations relative au BPO de l'item chargé
     * @var	Object
     */
    public $bpo;

    /**
     * Contient un pointeur vers le bpo parent de cet item
     * @var	Pointeur
     */
    public $parentBPO;

    /**
     * Niveau de récupération de l'objet, pour le listing de ses composants
     * @var	int
     */
    public $hierarchieLevel;

    /**
     * Quantité de cet item requis pour le BPO parent
     * @var	int
     */
    public $qttRequired;

    /**
     * Quantité d'item requis
     * @var	array
     */
    public $requiredComp;

    /**
     * Prix de l'item
     * @var	float
     */
    public $price;

    /**
     * Temps de production de l'objet
     * @var	int
     */
    public $productionTime;

    /**
     * Cout de production d'un item (pour le nombre requis)
     * @var	int
     */
    public $productionCost;

    /**
     * Surcharge du constructeur parent pré-paramétré
     * @param	int	$typeID		    Identifiant de l'item à récupérer
     * @param	int	$hierarchieLevel    Niveau de récupération de l'objet, pour le listing de ses composants
     * @param	int	$qttRequired	    Quantité requise pour le BPO parent
     * @param	&	$parentBPO	    Pointeur vers le BPO parent
     * @return	$this
     */
    public function __construct($typeID, $hierarchieLevel = 0, $qttRequired = 1, $parentBPO = NULL){
		/* Seulement si on à bien spécifier un ID */
		if(!empty($typeID)){
			/* Ajout des paramètres */
			$this->hierarchieLevel = $hierarchieLevel;
			$this->qttRequired = $qttRequired;
			$this->parentBPO = $parentBPO;

			/* Appel au constructeur de Dao */
			parent::__construct($this->_base, $this->_table, $this->_readOnly);

			/* Renvoit de l'état de $this->load() */
			return $this->load($typeID);
		}else{
			exit();
		}
    }

    /**
     * Surcharge de la fonction parent load lancant automatiquement les méthodes
     * de récupération de matériaux
     * @param	int	$id	ID à charger
     * @return  bool
     * @access	public
     */
    public function load($id = null, $column = null, $order = null, $forceReload = false) {
		/* Chargement du BPO que si le chargement de la ligne est bon
		 * et que ce n'est un pas item considéré comme "de base"
		 */
		if(parent::load($id, $column, $order, $forceReload)){

			/* Chargment du prix */
			$this->loadPrice();

			/* Chargement des matériaux si ce n'est pas un item de base */
			if(!EveMath::isBaseMaterial($this->marketGroupID)){
				/* Récupération de son BPO */
				$this->bpo = new evebpo($this);

				if(!empty($this->bpo->blueprintTypeID)) {
					/* Récupération de la liste des items nécessaire à la manufacture (activity = 1)*/
					$list = $this->bpo->requiredComp(1);

					/* Chargement des item requis pour produire cet item */
					foreach($list AS $typeID => $qtt) {
						$this->requiredComp[$typeID] = new eveitem($typeID, $this->hierarchieLevel + 1, $qtt, $this->bpo);
					}

					/* Procédures à suivre pour les items T2 */
					if(EveMath::canBeInvented($this->bpo) && !$this->bpo->carac->exist()){
						/* Recherche du modèle T1 si on recherche les donnée d'un T2
						 * puis ajout aux item à ne pas appliquer au calcul de pertes
						 */
						$this->addBaseToAvoidWaste();

						/* Recherche de la nation de l'item si on l'a pas */
						if(empty($this->raceID))
							$this->loadNation();

						/* Sélection de la méthode d'invention */
						$this->bpo->selectInventionMethod();
					}

					/* Calcul du temps de prod de cet item */
					$this->productionTime = EveMath::productionTime($this->bpo);

					/* Calcul du cout des installations pour la production */
					$tmpQtt = $this->adjustQtt();

					/* Cout de prod = temps de location en heure * cout de location * qtt + cout d'installation */
					$this->productionCost = round(($this->productionTime / 3600) * BASELOCATIONCOST * $tmpQtt + BASEINSTALLATIONCOST, 2);

					return TRUE;
				} else {
					/* Si il n'existe pas de BPO pour cet item, on détruit la variable */
					unset($this->bpo);
					return FALSE;
				}
			}
		}

		return FALSE;
    }

    /**
     * Récupère le prix de cet item
     * @access	Private
     */
    private function loadPrice() {
		/* Si on à bien un ID et qu'on peu charger son prix */
		if(!empty($this->typeID) && !EveMath::includeCost($this->groupID)){
			/* Récupération du prix */
			$price = EveMath::getPrice(array($this->typeID));
			$this->price = $price[$this->typeID];
		}else
			$this->price = 0;
    }

    /**
     * Récupère la nation de cet item si elle est introuvable à partir de son BPO
     * @access	private
     */
    private function loadNation() {
		/* Récupération de l'id de l'interface à utiliser pour l'invention */
		switch($this->bpo->getInterfaceID()){
			case 25553:
				$this->raceID = 2; // Matar
				break;
			case 25554:
				$this->raceID = 4; // Amarr
				break;
			case 25555:
				$this->raceID = 1; // Calda
				break;
			case 25556:
				$this->raceID = 8; // Gallente
				break;
		}
    }

    /**
     * Récupère la version T1 de l'item regardé, et ajoute à EveMath pour
     * ne pas y appliquer le wastage factor
     * @access	private
     */
    private function addBaseToAvoidWaste() {
		/* Récupération de l'ID du T1 : */
		$sql = "SELECT i.parentTypeID
			FROM invmetatypes AS i
			WHERE i.typeID = " . $this->bpo->productTypeID;

		$req = Sql::run($sql, $this->_bdd);

		EveMath::addAvoidID($req[0]["parentTypeID"]);
    }

    /**
     * Renvois la liste des raw requis pour la production de l'item
     * @return	array	[ID][Propriété] = mixed $valeur
     * @access	public
     */
    public function recursiveNeed(){
		/* Ajustement de la quantité requise avec le gaspillage */
		$qtt = $this->adjustQtt();

		/* Si cette item est un embranchement */
		if(!empty($this->requiredComp)){
			foreach($this->requiredComp AS $typeID => $item){
			$list = $item->recursiveNeed();

				foreach($list AS $typeID => $detail){
					$send[$typeID]["qtt"] += $detail["qtt"] * $qtt;
					$send[$typeID]["nom"] = $detail["nom"];
					$send[$typeID]["market"] = $detail["market"];
					$send[$typeID]["prix"] = $detail["prix"];
					$send[$typeID]["volume"] = $detail["volume"];
				}
			}
		} else {
			/* Sinon on renvoit ses caractéristiques */
			$send[$this->typeID]["qtt"] += $qtt;
			$send[$this->typeID]["nom"] = $this->typeName;
			$send[$this->typeID]["market"] = $this->marketGroupID;
			$send[$this->typeID]["prix"] = $this->price;
			$send[$this->typeID]["volume"] = $this->volume;
		}

		return $send;
    }

    /**
     * Renvois la liste des raw requis pour la production de l'item
     * Contrairement à recursiveNeed() cette méthode ne donne les besoins
     * que du BPO de CET ITEM.
     * @return	array	[ID][Propriété] = mixed $valeur
     * @access	public
     */
    public function basicNeed() {
		/* Ajustement de la quantité requise avec le gaspillage */
		$qtt = $this->adjustQtt();

		/* Si cette item à bien des compos */
		if(!empty($this->requiredComp)) {
			foreach($this->requiredComp AS $typeID => $item) {
				$send[$typeID]["qtt"] += $item->adjustQtt() * $qtt;
				$send[$typeID]["nom"] = $item->typeName;
				$send[$typeID]["market"] = $item->marketGroupID;
				$send[$typeID]["prix"] = $item->price;
				$send[$typeID]["volume"] = $item->volume;
			}
		}else
			$send = FALSE;

		return $send;
    }

    /**
     * Ajustement des quantités avec la gaspillage
     * @return	int	Quantité requise
     * @access	public
     */
    private function adjustQtt() {
		/* Ajustement de la quantité requise avec le gaspillage */
		return $this->qttRequired
			+ (EveMath::haveToApplyWaste($this->groupID, $this->typeID) ?
			EveMath::waste($this->parentBPO->carac->me, $this->qttRequired, $this->parentBPO->wasteFactor) : 0);
    }

    /**
     * Renvoit la somme des compo servant à la prod de cet item
     * @return	float
     */
    public function recursivePrice() {
		/* Ajustement de la quantité requise avec le gaspillage */
		$qtt = $this->adjustQtt();

		/* Si cet objet a besoin d'item pour être prod */
		if(!empty($this->requiredComp)){
			foreach($this->requiredComp AS $typeID => $item){
				$total += $item->recursivePrice();
			}
			$total *= $qtt;
		/* Sinon si on à pas besoin d'autre item que lui même */
		}else{
			/* Sinon fin de récursion, on renvoit le prix * qtt */
			$total = $this->price->buy * $qtt;
		}

		return $total;
    }

    /**
     * Renvoit le cout total des installations
     * @return	int	Cout des installations
     * @access	public
     */
    public function recursiveProdCost() {
	/* Si cet objet a besoin d'item pour être prod */
	if(!empty($this->requiredComp)){
	    foreach($this->requiredComp AS $typeID => $item){
			$total += $item->recursiveProdCost();
	    }
	    $total += $this->productionCost;
	/* Sinon si on à pas besoin d'autre item que lui même */
	}else{
	    /* Sinon fin de récursion, on renvoit le prix */
	    $total = 0;
	}

	return $total;
    }

    /**
     * Renvoit le volume totale des composants requis
     * @return	float	Volume des composantes
     * @access	public
     */
    public function recursiveVolume() {
		/* Ajustement de la quantité requise avec le gaspillage */
		$qtt = $this->adjustQtt();

		/* Si cet objet a besoin d'item pour être prod */
		if(!empty($this->requiredComp)){
			foreach($this->requiredComp AS $typeID => $item){
				$total += $item->recursiveVolume();
			}
			$total *= $qtt;
		/* Sinon si on à pas besoin d'autre item que lui même */
		}else{
			/* Sinon fin de récursion, on renvoit le volume * qtt */
			$total = $this->volume * $qtt;
		}

		return $total;
    }
}
?>
